<?php


namespace app\live\controller\v2;


use app\aliyun\controller\AliyunLive;
use app\aliyun\controller\AliyunRtc;
use app\chat\LiveMessage;
use app\common\cachemodel\live\LiveAnchorInfo;
use app\common\cachemodel\live\LiveOrderData;
use app\common\cachemodel\live\LiveRecordingInfo;
use app\common\cachemodel\live\LiveRecordUserHot;
use app\common\cachemodel\live\LiveRtcRecord;
use app\common\cachemodel\live\LiveUserContribution;
use app\common\cachemodel\ZlUserVip;
use app\common\lib\Util;
use app\common\model\User;
use app\live\controller\LiveAuth;
use GatewayWorker\Lib\Gateway;
use think\Cache;
use think\response\Json;
use XznsTools\cache\CacheManage;

class LiveRtc extends LiveAuth
{
    /**
     * 生成 客户端调用RTC_SDK加入房间的Token信息
     */
    public function getRtcAuth(): Json
    {
        //todo 主播端创建频道 参数待定
        $result = (new AliyunRtc())->getRtcAuth(1, $this->liveInfo['live_id'], 'pub');
        if (empty($result))
        {
            return show(config('code.error'), '服务异常');
        }
        return show(config('code.success'), '请求成功', $result);
    }

    /**
     * 开始旁路直播
     */
    public function startMPUTask(): Json
    {
        $title = input('title/s', '');
        $liveContent = input('live_content/s', '');
        $cameraStatus = input('camera_status/d', 1);
        $radioStatus = input('radio_status/d', 1);
        $channelId = input('channel_id/s', '');

        $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);
        $record = (new LiveRecordingInfo())->getInfoById($liveRecordId, ['status', 'push_url', 'live_type']);
        if ($record['status'] == 1)
        {   // 继续直播
            if (isset($record['live_type']) && $record['live_type'] == 3)
            {   // 当前为录播
                return show(config('code.error'), '录播中,请先关闭录播再发起直播～');
            }
            $cameraRadioStatus = Cache::get('live:camera_radio_status' . $this->liveInfo['live_id']);

            if (empty($cameraRadioStatus)
                || !isset($cameraRadioStatus['camera_status'], $cameraRadioStatus['radio_status'])
                || $cameraRadioStatus['camera_status'] != $cameraStatus
                || $cameraRadioStatus['radio_status'] != $radioStatus)
            {   // 摄像头或麦克风 开启状态 更新
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ALL, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_CHANGE_CAMERA_RADIO, [
                        'camera_status' => $cameraStatus,
                        'radio_status' => $radioStatus,
                    ]);
                Cache::set('live:camera_radio_status' . $this->liveInfo['live_id'], [
                    'camera_status' => $cameraStatus,
                    'radio_status' => $radioStatus,
                ], 86400 * 2);
            }
            $taskId = Cache::get('live:startMPUTask:taskId:' . $this->liveInfo['live_id'], false);
            if ($taskId)
            {
                // 关闭旧的        旁路直播
                $result = (new AliyunRtc())->stopMPUTask($taskId);
                if ($result['code'] !== 200)
                {
                    return show(config('code.error'), $result['msg']);
                }
            }
            //开始旁路直播
            $result = (new AliyunRtc())->startMPUTask($channelId, $record['push_url']);
            if ($result['code'] !== 200)
            {
                return show(config('code.error'), $result['msg']);
            }
            Cache::set('live:startMPUTask:taskId:' . $this->liveInfo['live_id'], $result['data']['task_id'], 86400 * 2);
            //开始订阅事件
            $result = (new AliyunRtc())->createEventSubscribe($channelId, $result['data']['task_id']);
            if ($result['code'] !== 200)
            {
                return show(config('code.error'), $result['msg']);
            }
            //
            // //5.主播回来了【按home键-》重新打开App；杀掉App-》（主播端肯定点击“继续直播”，所以，在继续直播的时候，发个消息）；崩溃拦截-》（主播端肯定点击“继续直播”，所以，在继续直播的时候，发个消息）】
            LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ALL, $this->liveInfo['live_id'], $this->liveInfo['live_id']), LiveMessage::MSG_TYPE_LIVER_STATUS, 1);

            Cache::set('live:live_status:' . $this->liveInfo['live_id'] . ':' . $liveRecordId, 1, 18000);

            return show(config('code.success'), '请求成功', [
                'push_data_url' => $record['push_url'],
                'live_record_id' => $liveRecordId,
            ]);
        }

        if (empty($title))
        {
            return show(config('code.error'), '直播标题不能为空！');
        }
        if (empty($liveContent))
        {
            return show(config('code.error'), '直播内容不能为空！');
        }
        if (mb_strlen($title) > 15)
        {
            return show(config('code.error'), '直播标题不能不能超过15字！');
        }
        if (mb_strlen($liveContent) > 50)
        {
            return show(config('code.error'), '直播内容不能不能超过50字！');
        }

        // 初始化用户热度表
        if (!(new LiveRecordUserHot())->createUserHotTable($this->liveInfo['live_id']))
        {
            return show(config('code.error'), '服务异常，请稍后再试～');
        }

        $data = [
            'live_id' => $this->liveInfo['live_id'],
            'status' => 1,
            'title' => $title,
            'content' => $liveContent,
            'live_start_time' => $this->request->time(),
        ];

        $liveRecordId = (new LiveRecordingInfo())->addLive($data);

        //直播地址
        $liveUrl = (new AliyunLive())->createLive($this->liveInfo['live_id'], $liveRecordId);

        (new LiveRecordingInfo())->updateData($liveRecordId, [
            'push_url' => $liveUrl['push_url'],
            'pull_url' => json_encode($liveUrl['pull_url'], JSON_UNESCAPED_UNICODE),
            'pull_url_definition_list' => json_encode($liveUrl['pull_url_definition_list'], JSON_UNESCAPED_UNICODE),
        ]);
        //开始旁路直播
        $result = (new AliyunRtc())->startMPUTask($channelId, $liveUrl['push_url']);
        if ($result['code'] !== 200)
        {
            return show(config('code.error'), $result['msg']);
        }
        Cache::set('live:startMPUTask:taskId:' . $this->liveInfo['live_id'], $result['data']['task_id'], 86400 * 2);
        //开始订阅事件
        $result = (new AliyunRtc())->createEventSubscribe($channelId, $result['data']['task_id']);
        if ($result['code'] !== 200)
        {
            return show(config('code.error'), $result['msg']);
        }

        if ($liveRecordId)
        {
            Cache::set('live:camera_radio_status' . $this->liveInfo['live_id'], [
                'camera_status' => $cameraStatus,
                'radio_status' => $radioStatus,
            ], 86400 * 2);

            Util::queuePush('live_subscribe_send', ['live_info' => $this->liveInfo], 300);

            return show(config('code.success'), '请求成功', [
                'push_data_url' => $liveUrl['push_url'],
                'live_record_id' => $liveRecordId,
            ]);
        } else
        {
            return show(config('code.error'), '服务异常');
        }
    }

    /**
     * 连麦、推流状态更新
     * 主播端（拍摄的手机），根据rtc sdk的回调状态，请求接口：
     * 1.用户连麦成功：
     *      1.给连麦的用户端，发送连麦成功的消息；（可以挂断）
     *      2.给看 直播的用户 和 主播端，发送 连麦中的消息（啥信息也没有）；
     *      3.给用户管理端，发送连麦中的消息（可以挂断）
     * 2.用户端/主播端，连麦异常下线：
     *      1.给看 直播的用户，发送 隐藏连麦pop的消息；
     *      2.给用户主播端和主播端，发送 隐藏连麦pop的消息，并且toast提示；
     * 3.用户端/主播端，网络状态改变：
     *      给用户端/主播端/用户主播端，发送 连麦pop的 用户名/主播的网络***的消息；
     * 4.主播离开一会
     *      1.按home键；
     *      2.杀掉App；
     *      3.崩溃拦截；
     * 5.主播回来了
     *      1.按home键-》重新打开App；
     *      todo 2.杀掉App-》（？）；
     *      todo 3.崩溃拦截-》（？）；
     */
    public function updateStatus()
    {

        $status = input('status/d', 0);
        switch ($status)
        {
            case 0:
            {

                break;
            }
            case 1:
            {//1.用户连麦成功：
//                请求参数
//                @{@"uid":userId}];

                break;
            }
            case 2:
            {//2.用户端/主播端，连麦异常下线：
//                请求参数
//                @{@"uid":userId}];

                break;
            }
            case 3:
            {//3.用户端/主播端，网络状态改变：
//                请求参数
//                @{@"uid":uid,@"up_network_code":@(upQuality),@"down_network_code":@(downQuality)}

//                网络质量参考：
//                /** 网络极好，流程度清晰度质量好 */
//                AlivcRtcNetworkQualityExcellent = 0,
//                /** 网络好，流畅度清晰度和极好差不多 */
//                AlivcRtcNetworkQualityGood = 1,
//                /** 网络较差，音视频流畅度清晰度有瑕疵，不影响沟通 */
//                AlivcRtcNetworkQualityPoor = 2,
//                /** 网络差，视频卡顿严重，音频能正常沟通 */
//                AlivcRtcNetworkQualityBad = 3,
//                /** 网络极差，基本无法沟通 */
//                AlivcRtcNetworkQualityVeryBad = 4,
//                /** 网络中断 */
//                AlivcRtcNetworkQualityDisconnect = 5,
//                /** 未知 */
//                AlivcRtcNetworkQualityUnknow = 6,
                $uid = input('uid/d', 0);
                $upNetwork = input('up_network_code/d', 0);
                $downNetwork = input('down_network_code/d', 0);
                // 当前网络状态 1=>正常 2=>异常（网络差）
                $nowNerworkStatus = 1;
                if (in_array($upNetwork, [3, 4, 5, 6], true) || in_array($downNetwork, [3, 4, 5, 6], true))
                {   // 上行 或 下行 网络差
                    $nowNerworkStatus = 2;
                }
                // 获取最新的直播记录ID
                $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);
                $rtcRecordModel = new LiveRtcRecord();
                // 获取当前连麦状态信息
                $nowRtcData = $rtcRecordModel->getNowRtcDataByCache($liveRecordId);
                if ($nowRtcData)
                {
                    if (isset($nowRtcData['network_status'], $nowRtcData['live_network_status'], $nowRtcData['user_network_status']))
                    {
                        $nowRtcData['live_network_status'] = (int)$nowRtcData['live_network_status'];
                        $nowRtcData['user_network_status'] = (int)$nowRtcData['user_network_status'];
                        $changeStatus = false;
                        if ($uid === 1)
                        {   // 主播 网络状态
                            if ($nowNerworkStatus !== $nowRtcData['live_network_status'])
                            {
                                $changeStatus = true;
                            }
                            $nowRtcData['live_network_status'] = $nowNerworkStatus;
                        } else
                        {   // 用户网络状态
                            if ($nowNerworkStatus !== $nowRtcData['user_network_status'])
                            {
                                $changeStatus = true;
                            }
                            $nowRtcData['user_network_status'] = $nowNerworkStatus;
                        }
                    } else
                    {
                        $changeStatus = true;
                        $nowRtcData['live_network_status'] = $uid === 1 ? $nowNerworkStatus : 1;
                        $nowRtcData['user_network_status'] = $uid === 1 ? 1 : $nowNerworkStatus;
                    }

                    if ($changeStatus)
                    {
                        $nowRtcData['network_status'] = $nowRtcData['live_network_status'] === 1 && $nowRtcData['user_network_status'] === 1 ? 1 : 2;
                        // 保存当前 网络状态
                        $rtcRecordModel->saveNowRtcDataToCache($liveRecordId, $nowRtcData);

                        $networkDesc = $rtcRecordModel->getRtcNetworkStatusDesc($nowRtcData['live_network_status'], $nowRtcData['user_network_status']);

                        // 拼接 发送给 连麦用户 数据
                        $popMsgRtc2RtcUser = [
                            'type' => 1,
                            'toast' => '',
                            'user_info' => [
                                'name' => $this->liveInfo['name'],
                                'avatar' => $this->liveInfo['avatar'],
                                'uen' => $nowRtcData['uen'],
                                'status' => $nowRtcData['network_status'],
                                'des_network' => $networkDesc['user_network_desc'],
                            ],
                            'btn_list' => [
                                [
                                    'type' => 1,
                                    'title' => '挂断',
                                    'target' => 'api',
                                    'link' => '/api/v29/rtc_interaction?action=3&live_record_id=' . $liveRecordId . '&need_auth=2',
                                    'mic_auth_deny' => null,
                                    'action' => 2,
                                ],
                            ],
                        ];
                        // 拼接 发送给管理端 数据
                        $popMsgRtc2Admin = [
                            'type' => 1,
                            'toast' => '',
                            'user_info' => [
                                'name' => $nowRtcData['nickname'],
                                'avatar' => $nowRtcData['avatar'],
                                'uen' => $nowRtcData['uen'],
                                'status' => $nowRtcData['network_status'],
                                'des_network' => $networkDesc['live_network_desc'],
                            ],
                            'btn_list' => [
                                [
                                    'type' => 1,
                                    'title' => '挂断',
                                    'target' => 'api',
                                    'link' => '/live/v2/live/request_rtc_interaction?action=5&need_auth=2',
                                    'mic_auth_deny' => null,
                                    'action' => 2,
                                ],
                            ],
                        ];
                        // 向连麦用户发送消息
                        LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], (string)$uid)
                            , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2RtcUser);
                        // 向管理员 发送消息
                        LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                            , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2Admin);
                    }
                }

                break;
            }
            case 4:
            {//4.主播离开一会 【按home键；杀掉App；崩溃拦截；】
                // 获取最新的直播记录ID
                $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);
                Cache::set('live:live_status:' . $this->liveInfo['live_id'] . ':' . $liveRecordId, 0, 18000);
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ALL, $this->liveInfo['live_id'], $this->liveInfo['live_id']), LiveMessage::MSG_TYPE_LIVER_STATUS, 0);
                break;
            }
            case 5:
            {//5.主播回来了【按home键-》重新打开App；杀掉App-》（主播端肯定点击“继续直播”，所以，在继续直播的时候，发个消息）；崩溃拦截-》（主播端肯定点击“继续直播”，所以，在继续直播的时候，发个消息）】
                $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);
                Cache::set('live:live_status:' . $this->liveInfo['live_id'] . ':' . $liveRecordId, 1, 18000);
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_ALL, $this->liveInfo['live_id'], $this->liveInfo['live_id']), LiveMessage::MSG_TYPE_LIVER_STATUS, 1);
                break;
            }
            default:
            {
                return show(config('code.error'), 'status 参数错误！');
            }
        }
        //todo 发送消息


        return show(config('code.success'), '发送成功！');
    }

    /**
     * 接受｜拒绝 ｜邀请｜取消｜挂断连麦
     */
    public function requestRtcInteraction(): Json
    {
        $id = input('id/d', 0);//申请连麦ID【仅接受和拒绝必传】
        $action = input('action/d', 0);//操作 1=>接受连麦 2=>拒绝连麦  3=>邀请   4=>取消   5=>挂断
        $uen = input('uen/s', '');//准了号【仅邀请连麦必传】

        if (!in_array($action, [1, 2, 3, 4, 5], true))
        {
            return show(config('code.error'), '请求失败，请稍后再试～');
        }

        // 获取最新的直播记录ID
        $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);

        $rtcRecordModel = new LiveRtcRecord();
        switch ($action)
        {
            case 1:
            case 3:
                $nowRtcData = $rtcRecordModel->getNowRtcDataByCache($liveRecordId);
                if ($nowRtcData)
                {
                    return show(config('code.error'), '正在连麦请求中，连麦失败～');
                }

                if ($action === 1)
                {
                    $questionRtcInfo = $rtcRecordModel->getInfoById($id);
                    if (!$questionRtcInfo)
                    {
                        return show(config('code.error'), '服务异常，申请连麦信息不存在～');
                    }

                    if ((int)$questionRtcInfo['status'] === 14)
                    {
                        return show(config('code.error'), '用户已取消连麦申请');
                    }
                    if (!LiveMessage::getUidIsOnline($this->liveInfo['live_id'], $questionRtcInfo['uid']))
                    {   // 用户不在线
                        return show(config('code.error'), '用户已离线，连麦邀请失败～');
                    }
                    // 更新连麦状态
                    $rtcRecordModel->updateRtcInfo($id, ['status' => 2, 'update_time' => $this->request->time()]);

                    $userInfo = current((new User())->batchGetUserInfo([$questionRtcInfo['uid']]));
                } else
                {
                    $uid = (new \app\common\cachemodel\User())->getUidByUen($uen);
                    Gateway::$registerAddress = config('websocket.register_ip') . ':' . config('websocket.register_port');
                    $clientIds = Gateway::getClientIdByUid($uid);
                    $isOnline = false;
                    $clientSession = null;
                    foreach ($clientIds as $clientId)
                    {
                        //获取指定客户端session
                        $info = Gateway::getSession($clientId);
                        //判断当前直播间是否存在
                        if ($this->liveInfo['live_id'] === (int)$info['live_id'])
                        {
                            $isOnline = true;
                            $clientSession = $info;
                            break;
                        }
                    }

                    if (!$isOnline)
                    {   // 用户不在线
                        return show(config('code.error'), '用户已离线，连麦邀请失败～');
                    }

                    if (Util::CheckAppVersion('2.7.3', $clientSession['version']) !== '大')
                    {
                        return show(config('code.error'), '用户APP版本过低，连麦邀请失败～');
                    }

                    $userInfo = current((new User())->batchGetUserInfo([$uid]));
                }

                $newRtcData = [
                    'id' => $action === 1 ? $id : 0, // 连麦ID    ID==0 为邀请连麦  否则为主播接受连麦
                    'rtc_sign' => uniqid(),
                    'type' => $action === 1 ? 1 : 2,    // 1=>接受连麦  2=>邀请连麦
                    'live_id' => $this->liveInfo['live_id'],
                    'uid' => $userInfo['id'],
                    'nickname' => $userInfo['nickname'] ?? '',
                    'avatar' => $userInfo['avatar'] ?? '',
                    'uen' => $userInfo['uen'] ?? '',
                    'status' => 1,  // 当前连麦状态 1=>邀请等待用户接受 2=>用户接受开始连麦中 3=>连麦成功 连麦中
                    'request_time' => $this->request->time(),   // 邀请用户连麦时间
                ];

                $resStatus = $rtcRecordModel->saveNowRtcDataToCache($liveRecordId, $newRtcData);

                if (!$resStatus)
                {
                    return show(config('code.error'), '服务异常，连麦失败');
                }
                // 拼接 发送给所有用户 数据
                $popMsgRtc2All = [
                    'type' => 1,
                    'toast' => '',
                    'user_info' => [
                        'name' => $userInfo['nickname'],
                        'avatar' => $userInfo['avatar'],
                        'uen' => $userInfo['uen'],
                        'status' => 0,
                        'des_network' => '',
                    ],
                    'btn_list' => [
                        [
                            'type' => 2,
                            'title' => '等待接听中…',
                            'target' => '',
                            'link' => '',
                            'mic_auth_deny' => null,
                            'action' => 0,
                        ],
                    ],
                ];
                // 拼接 发送给 连麦用户 数据
                $popMsgRtc2RtcUser = [
                    'type' => 1,
                    'toast' => '',
                    'user_info' => [
                        'name' => $this->liveInfo['name'],
                        'avatar' => $this->liveInfo['avatar'],
                        'uen' => $userInfo['uen'],
                        'status' => 0,
                        'des_network' => '',
                    ],
                    'btn_list' => [
                        [
                            'type' => 1,
                            'title' => '接听',
                            'target' => 'api',
                            'link' => '/api/v29/rtc_interaction?action=1&live_record_id=' . $liveRecordId . '&need_auth=2',
                            'mic_auth_deny' => [
                                'target' => 'api',
                                'link' => '/api/v29/rtc_interaction?action=2&live_record_id=' . $liveRecordId . '&need_auth=2',
                            ],
                            'action' => 1,
                        ], [
                            'type' => 1,
                            'title' => '拒绝',
                            'target' => 'api',
                            'link' => '/api/v29/rtc_interaction?action=2&live_record_id=' . $liveRecordId . '&need_auth=2',
                            'mic_auth_deny' => null,
                            'action' => 3,
                        ], [
                            'type' => 2,
                            'title' => '主播申请语音连麦',
                            'target' => '',
                            'link' => '',
                            'mic_auth_deny' => null,
                            'action' => 0,
                        ],
                    ],
                ];
                // 拼接 发送给管理端 数据
                $popMsgRtc2Admin = [
                    'type' => 1,
                    'toast' => '',
                    'user_info' => [
                        'name' => $userInfo['nickname'],
                        'avatar' => $userInfo['avatar'],
                        'uen' => $userInfo['uen'],
                        'status' => 0,
                        'des_network' => '',
                    ],
                    'btn_list' => [
                        [
                            'type' => 1,
                            'title' => '取消连麦',
                            'target' => 'api',
                            'link' => '/live/v2/live/request_rtc_interaction?action=4&need_auth=2',
                            'mic_auth_deny' => null,
                            'action' => 4,
                        ], [
                            'type' => 2,
                            'title' => '等待接听中…',
                            'target' => '',
                            'link' => '',
                            'mic_auth_deny' => null,
                            'action' => 0,
                        ],
                    ],
                ];
                $userClientId = LiveMessage::getClientIdByUid($userInfo['id']);
                // 向直播间所有人 发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_APP_USER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2All, $userClientId);
                // 向连麦用户发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], (string)$userInfo['id'])
                    , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2RtcUser);
                // 向管理员 发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2Admin);
                // 添加 超时检测 队列
                Util::queuePush('live_rtc_client_timeout_check', [
                    'live_record_id' => $liveRecordId,
                    'rtc_sign' => $newRtcData['rtc_sign'],
                    'status' => $newRtcData['status'],
                ], 30); //30 秒后 自动关闭

                return show(config('code.success'), '请求成功', $popMsgRtc2Admin);
            case 2:
                $questionRtcInfo = $rtcRecordModel->getInfoById($id);
                if (!$questionRtcInfo)
                {
                    return show(config('code.error'), '服务异常，申请连麦信息不存在～');
                }

                if ((int)$questionRtcInfo['status'] !== 1)
                {
                    return show(config('code.error'), '申请连麦信息状态异常，操作失败');
                }

                if ((int)$questionRtcInfo['status'] !== 13)
                {
                    $rtcRecordModel->rtcListDel($liveRecordId, (int)$questionRtcInfo['uid']);    // 删除从列表中移除
                } else
                {
                    // 更新连麦状态
                    $rtcRecordModel->updateRtcInfo($id, ['status' => 13, 'cancel' => $this->request->time(), 'update_time' => $this->request->time()]);
                    $rtcRecordModel->rtcListDel($liveRecordId, (int)$questionRtcInfo['uid']);    // 删除从列表中移除
                }

                // 向连麦用户发送 拒绝连麦消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], (string)$questionRtcInfo['uid'])
                    , LiveMessage::MSG_TYPE_TOAST, '已拒绝连麦');

                // 获取当前 rtc 开启状态
                $rtcSwitch = (int)(Cache::get("live:rtc_switch:{$this->liveInfo['live_id']}:{$liveRecordId}", 0));
                $allRequestRtcUserList = $rtcRecordModel->getRtcUserList($liveRecordId);
                unset($allRequestRtcUserList[$questionRtcInfo['uid']]);
                if ($allRequestRtcUserList)
                {
                    $adminRtcStatus = 3;
                } else
                {
                    $adminRtcStatus = $rtcSwitch;
                }

                // 向连麦用户发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], $questionRtcInfo['uid'])
                    , LiveMessage::MSG_TYPE_RTC_STATUS, $rtcSwitch);
                // 向直播间 管理员和主播 发送连麦 状态消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_RTC_STATUS, $adminRtcStatus);

                return show(config('code.success'), '操作成功');
            case 4:
                $nowRtcData = $rtcRecordModel->getNowRtcDataByCache($liveRecordId);
                if (!$nowRtcData)
                {
                    // 拼接 发送给管理端 数据
                    $popMsgRtc2Admin = [
                        'type' => 2,
                        'toast' => '已取消连麦',
                        'user_info' => null,
                        'btn_list' => [],
                    ];

                    return show(config('code.success'), '操作成功', $popMsgRtc2Admin);
                }

                if ((int)$nowRtcData['status'] === 3)
                {   // 连麦成功  禁止取消连麦  可进行挂断连麦
                    return show(config('code.error'), '连麦中，操作失败');
                }

                if ($nowRtcData['id'] > 0)
                {
                    $questionRtcInfo = $rtcRecordModel->getInfoById($nowRtcData['id']);
                    $status = (int)$nowRtcData['status'] === 1 ? 11 : 19;
                    // 更新连麦状态
                    $rtcRecordModel->updateRtcInfo($nowRtcData['id'], ['status' => $status, 'cancel' => $this->request->time(), 'update_time' => $this->request->time()]);
                    if ((int)$nowRtcData['type'] === 1)
                    {   // 用户申请
                        $rtcRecordModel->rtcListDel($liveRecordId, (int)$questionRtcInfo['uid']);    // 删除从列表中移除
                    }
                }
                $rtcRecordModel->delNowRtcDataByCache($liveRecordId);   // 删除当前连麦信息
                // 拼接 发送给所有用户 数据
                $popMsgRtc2All = [
                    'type' => 0,
                    'toast' => '',
                    'user_info' => null,
                    'btn_list' => [],
                ];

                // 拼接 发送给 连麦用户 数据
                $popMsgRtc2RtcUser = [
                    'type' => 2,
                    'toast' => '主播已取消连麦',
                    'user_info' => null,
                    'btn_list' => [],
                ];

                // 拼接 发送给管理端 数据
                $popMsgRtc2Admin = [
                    'type' => 2,
                    'toast' => '已取消连麦',
                    'user_info' => null,
                    'btn_list' => [],
                ];

                $userClientId = LiveMessage::getClientIdByUid($nowRtcData['uid']);
                // 向直播间所有人 发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_APP_USER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2All, $userClientId);
                // 向连麦用户发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], (string)$nowRtcData['uid'])
                    , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2RtcUser);
                // 向管理员 发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2Admin);

                // 获取当前 rtc 开启状态
                $rtcSwitch = (int)(Cache::get("live:rtc_switch:{$this->liveInfo['live_id']}:{$liveRecordId}", 0));
                $allRequestRtcUserList = $rtcRecordModel->getRtcUserList($liveRecordId);
                unset($allRequestRtcUserList[$nowRtcData['uid']]);
                if ($allRequestRtcUserList)
                {
                    $adminRtcStatus = 3;
                } else
                {
                    $adminRtcStatus = $rtcSwitch;
                }

                // 向连麦用户发送消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], $nowRtcData['uid'])
                    , LiveMessage::MSG_TYPE_RTC_STATUS, $rtcSwitch);
                // 向直播间 管理员和主播 发送连麦 状态消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_RTC_STATUS, $adminRtcStatus);

                return show(config('code.success'), '操作成功', $popMsgRtc2Admin);
            case 5:
                $nowRtcData = $rtcRecordModel->getNowRtcDataByCache($liveRecordId);
                if (!$nowRtcData)
                {
                    // 拼接 发送给所有用户 数据
                    $popMsgRtc2All = [
                        'type' => 0,
                        'toast' => '',
                        'user_info' => null,
                        'btn_list' => [],
                    ];
                    // 向直播间所有人 发送消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_APP_USER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                        , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2All);
                    // 拼接 发送给管理端 数据
                    $popMsgRtc2Admin = [
                        'type' => 2,
                        'toast' => '已挂断连麦',
                        'user_info' => null,
                        'btn_list' => [],
                    ];
                    // 向管理员 发送消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                        , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2Admin);

                    return show(config('code.success'), '操作成功', $popMsgRtc2Admin);
                }

                // 挂断
                $result = (new AliyunRtc())->removeTerminals($this->liveInfo['live_id'], [(int)$nowRtcData['uid']]);
                if ($result['code'] === 200)
                {   // 挂断成功
                    $rtcRecordModel->delNowRtcDataByCache($liveRecordId); // 删除当前连麦信息

                    $questionRtcInfo = $rtcRecordModel->getInfoById($nowRtcData['id']);
                    // 计算连麦时长
                    $duration = $this->request->time() - $questionRtcInfo['start_time'];
                    // 更新连麦记录
                    $rtcRecordModel->updateRtcInfo((int)$nowRtcData['id'], [
                        'status' => 4,
                        'duration' => $duration,
                        'cancel' => $this->request->time(),
                        'update_time' => $this->request->time(),
                    ]);

                    // 列表连麦信息删除
                    if ((int)$nowRtcData['type'] === 1)
                    {
                        $rtcRecordModel->rtcListDel($liveRecordId, (int)$questionRtcInfo['uid']);    // 删除从列表中移除
                    }

                    // 拼接 发送给所有用户 数据
                    $popMsgRtc2All = [
                        'type' => 0,
                        'toast' => '',
                        'user_info' => null,
                        'btn_list' => [],
                    ];

                    // 拼接 发送给 连麦用户 数据
                    $popMsgRtc2RtcUser = [
                        'type' => 2,
                        'toast' => '主播已挂断连麦',
                        'user_info' => null,
                        'btn_list' => [],
                    ];

                    // 拼接 发送给管理端 数据
                    $popMsgRtc2Admin = [
                        'type' => 2,
                        'toast' => '已挂断连麦',
                        'user_info' => null,
                        'btn_list' => [],
                    ];

                    $userClientId = LiveMessage::getClientIdByUid($nowRtcData['uid']);
                    // 向直播间所有人 发送消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_APP_USER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                        , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2All, $userClientId);
                    // 向连麦用户发送消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], (string)$nowRtcData['uid'])
                        , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2RtcUser);
                    // 向管理员 发送消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                        , LiveMessage::MSG_TYPE_POP_MSG_RTC, $popMsgRtc2Admin);

                    // 获取当前 rtc 开启状态
                    $rtcSwitch = (int)(Cache::get("live:rtc_switch:{$this->liveInfo['live_id']}:{$liveRecordId}", 0));
                    $allRequestRtcUserList = $rtcRecordModel->getRtcUserList($liveRecordId);
                    unset($allRequestRtcUserList[$questionRtcInfo['uid']]);
                    if ($allRequestRtcUserList)
                    {
                        $adminRtcStatus = 3;
                    } else
                    {
                        $adminRtcStatus = $rtcSwitch;
                    }

                    // 向连麦用户发送消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_UID, $this->liveInfo['live_id'], $questionRtcInfo['uid'])
                        , LiveMessage::MSG_TYPE_RTC_STATUS, $rtcSwitch);
                    // 向直播间 管理员和主播 发送连麦 状态消息
                    LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                        , LiveMessage::MSG_TYPE_RTC_STATUS, $adminRtcStatus);

                    return show(config('code.success'), '操作成功', $popMsgRtc2Admin);
                } else
                {   // TODO 提出连麦 失败异常处理
                    return show(config('code.error'), '服务异常，挂断失败');
                }
            default:
        }

        // 挂断
        $result = (new AliyunRtc())->removeTerminals($this->liveInfo['live_id'], $id);

        if ($result['code'] !== 200)
        {
            return show(config('code.error'), $result['msg']);
        }

        return show(config('code.success'), '发送成功！');
    }

    /**
     * 获取连麦设置
     */
    public function getRtcConfig()
    {
        $rtcConfig = (new LiveAnchorInfo())->getRtcConfig($this->liveInfo['live_id']);

        return show(config('code.success'), '请求成功', $rtcConfig);
    }

    /**
     * 更新连麦设置
     */
    public function setRtcConfig()
    {
        $rtcSwitch = input('rtc_switch/d', 99999);
        $rtcAuth = input('rtc_auth/d', 0);
        $rtcMaxUser = input('rtc_max_user/d', 0);

        $updateData = [];

        if (in_array($rtcSwitch, [1, 0], true))
        {
            $updateData['rtc_switch'] = $rtcSwitch;
        }

        if ($rtcAuth && in_array($rtcAuth, [1, 2, 3], true))
        {
            $updateData['rtc_auth'] = $rtcAuth;
        }

        if ($rtcMaxUser && in_array($rtcMaxUser, [5, 10, 20, 40, 50], true))
        {
            $updateData['rtc_max_user'] = $rtcMaxUser;
        }

        // -------   获取当前rtc配置
        $rtcConfig = (new LiveAnchorInfo())->getRtcConfig($this->liveInfo['live_id']);

        if ($updateData)
        {
            if (isset($updateData['rtc_auth']) || isset($updateData['rtc_max_user']))
            {   // 如果是连麦权限或者 连麦用户数量的变更
                $config = [
                    'rtc_auth' => $updateData['rtc_auth'] ?? $rtcConfig['rtc_auth'],
                    'rtc_max_user' => $updateData['rtc_max_user'] ?? $rtcConfig['rtc_max_user'],
                ];
                try
                {
                    (new LiveAnchorInfo())->setAnchorExtendConfig($this->liveInfo['live_id'], 'rtc_config', $config);
                }
                catch (\Exception $e)
                {
                    return show(config('code.error'), '设置失败', $rtcConfig);
                }

                $rtcConfig = array_merge($rtcConfig, $config);
            }

            if (isset($updateData['rtc_switch']))
            {
                // 获取最新的直播记录ID
                $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);
                $rtcConfig['rtc_switch'] = $updateData['rtc_switch'];
                $excludeClientIds = [];
                $liveRtcRecordModel = new LiveRtcRecord();
                $allRequestRtcUserList = $liveRtcRecordModel->getRtcUserList($liveRecordId);
                if ($rtcConfig['rtc_switch'] === 0)
                {
                    // 获取当前申请连麦的所有用户
                    if ($allRequestRtcUserList)
                    {
                        Gateway::$registerAddress = config('websocket.register_ip') . ':' . config('websocket.register_port');
                        foreach ($allRequestRtcUserList as $uid => $rtcId)
                        {
                            $clientId = Gateway::getClientIdByUid($uid);
                            if ($clientId)
                            {
                                $excludeClientIds[] = current($clientId);
                            }
                        }
                        $adminRtcStatus = 3;    // 主播端 连麦状态
                    } else
                    {
                        $adminRtcStatus = 0;
                    }
                } else
                {
                    if ($allRequestRtcUserList)
                    {
                        $adminRtcStatus = 3;
                    } else
                    {
                        $adminRtcStatus = 1;
                    }

                }
                // 向直播间所有 用户 发送 连麦申请开关状态 消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_APP_USER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_RTC_STATUS, $updateData['rtc_switch'], $excludeClientIds);

                // 向直播间 管理员和主播 发送连麦 状态消息
                LiveMessage::sendMsg(LiveMessage::who(LiveMessage::WHO_TYPE_LIVER, $this->liveInfo['live_id'], $this->liveInfo['live_id'])
                    , LiveMessage::MSG_TYPE_RTC_STATUS, $adminRtcStatus);
                Cache::set("live:rtc_switch:{$this->liveInfo['live_id']}:{$liveRecordId}", $rtcConfig['rtc_switch'], 86400);
            }

            return show(config('code.success'), '设置成功', $rtcConfig);
        } else
        {
            return show(config('code.error'), '设置失败', $rtcConfig);
        }
    }

    /**
     * 获取申请连麦用户列表
     * @return Json
     * @throws \Exception
     */
    public function getRequestRtcUserList()
    {
        $type = input('type/d', 0);  //0全部用户  1=>送礼物   2=>下单   3=>会员

        $liveRtcRecordModel = new LiveRtcRecord();
        // 获取最新的直播记录ID
        $liveRecordId = (new LiveRecordingInfo())->getNewestRecord($this->liveInfo['live_id']);
        // 获取当前 rtc开关开启状态
        $rtcSwitch = (int)(Cache::get("live:rtc_switch:{$this->liveInfo['live_id']}:{$liveRecordId}", 0));
        // 直播间在线用户列表
        $clientUserList = LiveMessage::getClientSessionsByGroup($this->liveInfo['live_id'] . '_app_user_group');
        $clientUserList = array_column($clientUserList, null, 'uid');
        unset($clientUserList[0]);
        // 获取当前申请连麦的所有用户
        $allRequestRtcUserList = $liveRtcRecordModel->getRtcUserList($liveRecordId);
        // $clientUserList = array_diff_key($clientUserList, $allRequestRtcUserList);
        // 获取当前的连麦信息
        $nowRtcData = $liveRtcRecordModel->getNowRtcDataByCache($liveRecordId);

        switch ($type)
        {
            case 1:
                $contributionList = (new LiveUserContribution())->getContributionRanking($this->liveInfo['live_id'], 1, 50);
                $uids = $contributionList['data'] ? array_column($contributionList['data'], 'uid') : [];
                $resUser = [];
                $requestRtcId = [];
                foreach ($uids as $uid)
                {
                    if (isset($allRequestRtcUserList[$uid]))
                    {
                        $requestRtcId[] = (int)$allRequestRtcUserList[$uid];
                    }
                    if (isset($clientUserList[$uid]))
                    {
                        $resUser[$uid] = $clientUserList[$uid];
                    }
                }
                break;
            case 2:
                $orderUids = (new LiveOrderData())->getLiveRecordOrderUid($liveRecordId);
                $resUser = [];
                $requestRtcId = [];
                foreach ($orderUids as $uid)
                {
                    if (isset($allRequestRtcUserList[$uid]))
                    {
                        $requestRtcId[] = (int)$allRequestRtcUserList[$uid];
                    }
                    if (isset($clientUserList[$uid]))
                    {
                        $resUser[$uid] = $clientUserList[$uid];
                    }
                }
                break;
            case 3:
                $allRequestRtcUserListUid = array_keys($allRequestRtcUserList);
                $resUser = [];
                $requestRtcId = [];
                foreach ($allRequestRtcUserListUid as $uid)
                {
                    if (isset($clientUserList[$uid]))
                    {
                        if ($clientUserList[$uid]['vip_level'] > 0)
                        {
                            $requestRtcId[] = (int)$allRequestRtcUserList[$uid];
                        }
                    } else
                    {
                        $vipLevel = (new ZlUserVip())->getUserVipLevel($uid);
                        if ($vipLevel > 0)
                        {   // 是VIP
                            $requestRtcId[] = (int)$allRequestRtcUserList[$uid];
                        }
                    }
                }

                foreach ($clientUserList as $uid => $clientUserItem)
                {
                    if ($clientUserItem['vip_level'] > 0)
                    {
                        $resUser[$uid] = $clientUserItem;
                    }
                }
                break;
            default:
                $requestRtcId = array_values($allRequestRtcUserList);
                $resUser = $clientUserList;
        }

        $requestRtcData = $requestRtcId ? $liveRtcRecordModel->batchGetInfoByIds($requestRtcId) : [];

        // 申请连麦用户
        $requestRtcUserList = [];
        foreach ($requestRtcData as $requestRtcDatum)
        {
            $onlineStatus = 0; // 1在线 0不在线
            if (isset($resUser[$requestRtcDatum['uid']]))
            {
                $onlineStatus = 1;
                $nickname = $resUser[$requestRtcDatum['uid']]['name'] ?? '';
                $avatar = $resUser[$requestRtcDatum['uid']]['avatar'] ?? '';
            } else
            {
                $userInfo = current((new User())->batchGetUserInfo([$requestRtcDatum['uid']]));
                $nickname = $userInfo['nickname'] ?? '';
                $avatar = $userInfo['avatar'] ?? '';
            }

            if ($nowRtcData && (int)$nowRtcData['id'] === (int)$requestRtcDatum['id'])
            {   // 当前连麦状态 1=>邀请等待用户接受 2=>用户接受开始连麦中 3=>连麦成功 连麦中
                $rtcStatus = (int)$nowRtcData['status'] === 3 ? 3 : 2;
            } else
            {
                $rtcStatus = 0;
            }

            $requestRtcUserList[] = [
                'id' => (int)$requestRtcDatum['id'],
                'nickname' => $nickname,
                'avatar' => $avatar,
                'online_status' => $onlineStatus,
                'request_time' => Sec2Time1($this->request->time() - $requestRtcDatum['application_time']),
                'rtc_status' => $rtcStatus,
                'question' => $requestRtcDatum['question'],
            ];
        }

        $resUser = array_diff_key($resUser, $allRequestRtcUserList);

        // 在线用户
        $onlineUserList = [];
        $clientNum = 100;
        if ($nowRtcData && isset($resUser[$nowRtcData['uid']]))
        {   // 当前连麦用户  放置 首位
            $rtcStatus = (int)$nowRtcData['status'] === 3 ? 3 : 2;
            $onlineUserList[] = [
                'nickname' => $resUser[$nowRtcData['uid']]['name'] ?? '',
                'avatar' => $resUser[$nowRtcData['uid']]['avatar'] ?? '',
                'uen' => $resUser[$nowRtcData['uid']]['uen'],
                'rtc_status' => $rtcStatus, // 连麦中
            ];

            $clientNum = 99;
            unset($resUser[$nowRtcData['uid']]);
        }
        $resUser = array_slice($resUser, 0, $clientNum, true); // 仅返回100位

        foreach ($resUser as $item)
        {
            $onlineUserList[] = [
                'nickname' => $item['name'] ?? '',
                'avatar' => $item['avatar'] ?? '',
                'uen' => $item['uen'],
                'rtc_status' => 0,
            ];
        }

        $resData = [
            'rtc_switch' => $rtcSwitch,
            'request_rtc' => $requestRtcUserList,
            'online_user_list' => $onlineUserList,
        ];

        return show(config('code.success'), '请求成功', $resData);
    }
}
